package org.tokaf.datasearcher;

import java.util.Iterator;

import org.tokaf.normalizer.Normalizer;
import org.tokaf.normalizer.SimpleNormalizer;

/**
 * <p>Interface, which allows to query data like an Iterator. However,
 * DataSearcher needs to be initialized with initSource and initSearch methods.</p>
 * <p>Certain DataSearchers allows direct access with findObject method.</p>
 * <p>Copyright (c) 2006</p>
 * @author Alan Eckhardt
 * @version 1.0
 */
public abstract class DataSearcher implements Iterator, Cloneable {

	protected Normalizer norm=getDefaultNormalizer();

	private double dataDerivation;

	protected String name;

	public long initSourceTime = -1;

	public long initSearchTime = -1;

	protected String userName;

	protected String password;

	public DataSearcher() {
	}

	/**
	 * Specifies, whether this DataSearcher needs to sort results manually.
	 * @return true, if manual sort is needed,<br> otherwise false.
	 */
	public abstract boolean needsSort();


	/**
	 * Return default normalizer, which transforms the objects of this datasearcher into a number.
	 * @return SimpleNormalizer.
	 */
	public abstract SimpleNormalizer getDefaultNormalizer();
	
	
	/**
	 * This method should be implemented, when neddsSort returns true. It will
	 * sort the results according to column index.
	 * @param index of sorting column.
	 * @throws UnsupportedOperationException
	 */
	public abstract void sort(int index) throws UnsupportedOperationException;

	/**
	 * This method is not implemented in DataSearchers.
	 */
	public void remove() {
		throw new UnsupportedOperationException();
	}

	/**
	 * @return the derivation in data. It must be entered manually (new).
	 */
	public double getDataDerivation() {
		return dataDerivation;
	}

	/**
	 * Sets the derivation in data. It must be entered manually (new).
	 * @param dataDerivation
	 */
	public void setDataDerivation(double dataDerivation) {
		this.dataDerivation = dataDerivation;
	}

	/**
	 * @return normalizer associated to this datasearcher.
	 */
	public Normalizer getNormalizer() {
		return norm;
	}

	/**
	 * Sets the normalizer, that will be associated to this datasearcher.
	 * @param n
	 */
	public void setNormalizer(Normalizer n) {
		this.norm = n;
	}

	/**
	 * @return true, if there are left rows, otherwise false.
	 */
	public abstract boolean hasNext();

	/**
	 * In top-k search, first value is the name of object, second is the name of
	 * propery and third is the attribute itself.
	 * @param index index of field to be returned.
	 * @return the current value of the field specified by index.
	 */
	public abstract Object getField(int index);

	/**
	 * @param index index of field to be returned.
	 * @param position Position of desired in the list.
	 * @return the value of the field specified by index of object at desired
	 *         position.
	 * @throws UnsupportedOperationException
	 */
	public abstract Object getFieldAtPosition(int index, int position)
			throws UnsupportedOperationException;

	/**
	 * Advances the iterator one step further.
	 * @return int
	 */
	public abstract int advance();

	/**
	 * Performs the query on database.
	 * @param query Query in correct querying language.
	 */
	public abstract void initSearch(String query);

	/**
	 * Performs the query on database. Also sets the name of datasearcher,
	 * usually is the name of predicate of triples.
	 * @param query Query in correct querying language.
	 * @param name Name of the language.
	 */
	public void initSearch(String query, String name) {
		this.name = name;
		initSearch(query);

	}

	/**
	 * Initializes database from given string. It can be the name of file or the
	 * name of database.
	 * @param db Name of database.
	 * @return 1 when succeeded.
	 */
	public abstract int initSource(String db);

	/**
	 * Initializes database from given datasearcher. It uses the same database.
	 * @param searcher Source datasearcher.
	 * @return 1 when succeeded.
	 */
	public abstract int initSource(DataSearcher searcher);

	/**
	 * Tries to find object obj in database. String returned by obj.toString
	 * must be equal to the string of object at given position. When so, value
	 * of field at index is returned. Typical use is in threshold algorithm -
	 * data[j].findObject(subject, 0, 2); Finds the object in column j, which
	 * matches the name of subject at first position, and returns the third
	 * position (which is the attribute value).
	 * @param obj Object that is searcher for.
	 * @param position Position, which should match the subject.
	 * @param index Index of field to be returned.
	 * @return The field at index, of object which matches given object.
	 * @throws UnsupportedOperationException
	 */
	public abstract Object findObject(Object obj, int position, int index)
			throws UnsupportedOperationException;

	/**
	 * @return current position in list.
	 */
	public abstract int getPosistion();

	/**
	 * Resets the search, returns back to the begging of list and performs other
	 * cleaning operations. There is no need to call initSearch or initSource
	 * before next search. After this method, DataSearcher should be fully
	 * initialized.
	 */
	public abstract void resetSearch();

	/**
	 * @return the name of DataSearcher.
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name of DataSearcher to given name.
	 * @param name
	 */
	public void setName(String name) {
		this.name = name;
	}

	public abstract Object clone();

	/**
	 * Sets login and password, which will be used to access the database.
	 * @param userName
	 * @param password
	 */
	public void setLogin(String userName, String password) {
		setPassword(password);
		setUserName(userName);
	}

	/**
	 * @return the password to database.
	 */
	public String getPassword() {
		return password;
	}

	/**
	 * Sets password, which will be used to access the database.
	 * @param password
	 */
	public void setPassword(String password) {
		this.password = password;
	}

	/**
	 * @return the user name to database.
	 */
	public String getUserName() {
		return userName;
	}

	/**
	 * Sets password, which will be used to access the database.
	 * @param userName
	 */
	public void setUserName(String userName) {
		this.userName = userName;
	}
}
